package com.zhq.security.auth.handler;

import com.zhq.security.auth.service.UserDetailServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;


@Service
public class LinkAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private static final long serialVersionUID = -6743567631108323096L;


    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserDetailServiceImpl userDetailService;

    @Autowired
    private PasswordEncoder passwordEncoder;


    /**
     * 判断密码是否匹配的,进行密码匹配
     * 这个userDetails是下面的方法返回的，其中在下面这个方法中主要就是从数据库中获取到相关的用户信息
     * 可以直接在这里写返回的实体类，也可以实现UserDetailService来完成。此处采用下面的这种功能
     * @param userDetails
     * @param usernamePasswordAuthenticationToken
     * @throws AuthenticationException
     */
    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
        //如果密码不相等的话则进行累加操作，达到五次以上锁定该账户。1分钟后重试（测试用）
        if (!passwordEncoder.matches(usernamePasswordAuthenticationToken.getCredentials().toString(),userDetails.getPassword())){
            Long increment = redisTemplate.opsForValue().increment(userDetails.getUsername());
            if(increment>5){
                //此时进行锁定
                redisTemplate.opsForValue().set(serialVersionUID+userDetails.getUsername(),"1",1, TimeUnit.MINUTES);
                //把对应的键也删除了
                redisTemplate.delete(userDetails.getUsername());
                throw new BadCredentialsException("账户已经锁定，请1分钟后重试");
            }
            //一定要记得
            throw new BadCredentialsException("账号或密码错误");
        }
    }


    /**
     *
     * @param s
     * @param usernamePasswordAuthenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected UserDetails retrieveUser(String s, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
        return userDetailService.loadUserByUsername(s);
    }
}
